#include <RenderSubSystem/cvIMRenderer/Line.h>
#include <RenderSubSystem/cvIRender.h>
#include <RenderSubSystem/cvIMRenderer/LineBatch.h>
#include <Logger/GlobalLogger.h>

namespace cvImmediateModeRenderer
{
	// OBJECT CONSTRUCTION
	cvPool  Line::m_pool(sizeof(Line));		//<memory source>
	cvPool	Line::m_structpool(sizeof(line_struct));	//<memory source>

	Line * Line::create()
	{	// create node and add it to the current renderinglayer.
		// (never think that we should add it also into collection!!)
		Line * new_node = new Line;
		new_node->m_layer->renderList.push_back(*new_node);
		new_node->m_target = ::new (m_structpool.malloc()) line_struct();
		new_node->color(cvRenderInterface::IRenderer::DrawColour);
		return new_node;
	}

	Line * Line::createSingleshot()
	{
		return new Line;
	}

	void * Line::operator new(size_t size)	{ return m_pool.malloc(); }

	Line::Line() : m_target(0)
	{}

	// OBJECT DESTRUCTION
	void Line::destroy()	{ delete this; }
	void Line::operator delete(void * ptr)	{ m_pool.free(ptr); }
	Line::~Line()
	{	// free m_target if it was allocated from <m_structpool>
		if(!m_collection)
		{
			m_structpool.free(m_target);
		}
	}

	void Line::purgeMemoryPool()
	{
		m_pool.purge_memory();
		m_structpool.purge_memory();
	}

	cvRenderInterface::CollectionNode * Line::createCollection()
	{
		return LineBatch::create();
	}

	// TODO: this is an general operation, move to parent class.
	cvRenderInterface::CollectionNode * Line::requestCollection()
	{	// TODO: use ordered map to pick the right collection
		using cvRenderInterface::renderinglist_t;
		using cvRenderInterface::CollectionNode;
		if(m_collection_alloctarget)
		{	// check if previous alloctarget is in range.
			if( m_collection_alloctarget->lowerBound() > m_draworder
				&& m_collection_alloctarget->higherBound() <= m_draworder )
			{
				return m_collection_alloctarget;
			}
		}
		// did not, do full search:
		for(renderinglist_t::iterator it = m_layer->renderList.begin(); it != m_layer->renderList.begin(); ++it)
		{
			if(it->isCollection() && it->collectionType() == PRIMITIVE_LINE)
			{
				CollectionNode * p = static_cast<CollectionNode*>(&*it);
				if( p->lowerBound() > m_draworder && p->higherBound() <= m_draworder )
				{
					m_collection_alloctarget = p;
					return p;
				}
			}
		}
		// main rendering list does not have collection for this primitive type, return null.
		return NULL;
	}

	void * Line::getStorgatePtr() const	{ return (void*)m_target; }

	void Line::remapStorgate(cvRenderInterface::CollectionNode * node, void * sourceptr, void * targetptr)
	{
		line_struct * psource =  static_cast<line_struct*>(sourceptr);
		line_struct * ptarget =  static_cast<line_struct*>(targetptr);
		if(node && targetptr != NULL)
		{
			if(psource)	{ *ptarget = *psource; }	// copy data into new target.
			// free possible private target.
			if(!m_collection)	{ m_structpool.free(m_target); }
		}
		else if(node == NULL && targetptr == NULL)
		{
			// allocate private target.
			ptarget = new (m_structpool.malloc()) line_struct();
			if(psource)	{ *ptarget = *psource; }
		}

		m_target = ptarget;
		m_collection = node;
	}

	void Line::processCollect(const cvObjects::BaseCameraObject * camera)
	{}

	void Line::processTransfer()
	{}

	void Line::processRender()
	{	// Draw single line
		glBegin(GL_LINES);
		glColor4fv((GLfloat*)&(m_target->c1));
		glVertex2fv((GLfloat*)&(m_target->v1));
		glColor4fv((GLfloat*)&(m_target->c2));
		glVertex2fv((GLfloat*)&(m_target->v2));
		glEnd();
	}

	void Line::verts(const cvVert &v1, const cvVert &v2)
	{
		m_target->v1 = v1;
		m_target->v2 = v2;
	}
	void Line::color(const RGBAf &col)
	{
		m_target->c1 = col;
		m_target->c2 = col;
	}
	void Line::colorv1(const RGBAf &col)	{ m_target->c1 = col; }
	void Line::colorv2(const RGBAf &col)	{ m_target->c2 = col; }

};
